package com.tools.web.interceptor.et;

import com.tools.common.io.ProfileKit;
import com.tools.common.object.Note;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import java.lang.reflect.Method;

/**
 * API 接口执行耗时拦截器切面
 * */
@Note("API 接口执行耗时拦截器切面")
public final class ApiExecTimeInterceptor implements HandlerInterceptor, ServletRequestListener {

    @Note("存储计时的开始")
    private static final String START = "api-exec-time-start";
    @Note("存储接口 URI 的 Key")
    private static final String URI = "api-exec-time-uri";

    @Note("服务器上下文路径")
    private static final String CONTEXT_PATH = ProfileKit.getString("server.servlet.context-path");

    @Note("是否开启全部接口的耗时统计日志打印。默认关闭")
    private boolean allApiNeedLogPrint = false;

    @Note("日志输出实例")
    private static final Logger LOGGER = LoggerFactory.getLogger(ApiExecTimeInterceptor.class);

    public ApiExecTimeInterceptor() {
        Boolean allApiNeedLogPrint = ProfileKit.getBoolean("exec-time-all-api-log-print");
        if(allApiNeedLogPrint != null) this.allApiNeedLogPrint = allApiNeedLogPrint;
    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(handler instanceof ResourceHttpRequestHandler) return true;
        if(allApiNeedLogPrint) return private_setStart(request);
        Method method = ((HandlerMethod) handler).getMethod();
        ApiExecTime classAno = method.getDeclaringClass().getAnnotation(ApiExecTime.class);
        if(classAno != null) {
            return private_setStart(request);
        }
        ApiExecTime methodAno = method.getAnnotation(ApiExecTime.class);
        if(methodAno != null) return private_setStart(request);
        return true;
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        ServletRequest request = sre.getServletRequest();
        Long start = (Long) request.getAttribute(START);
        if(start != null) {
            long end = System.currentTimeMillis();
            String uri = (String) request.getAttribute(URI);
            LOGGER.info("接口 【{}】 执行耗时 {} ms", uri, end - start);
        }
    }

    @Note("设置开始计时和接口 uri 进域里")
    private boolean private_setStart(HttpServletRequest request) {
        request.setAttribute(START, System.currentTimeMillis());
        String uri = request.getRequestURI();
        if(CONTEXT_PATH != null) {
            request.setAttribute(URI, uri.replace(CONTEXT_PATH, ""));
        }
        return true;
    }
}
